package iterator;

import global.GlobalConst;
import global.PageId;
import global.RID;
import global.SystemDefs;
import heap.HFPage;
import heap.Heapfile;
import heap.InvalidSlotNumberException;
import heap.InvalidTupleSizeException;
import heap.InvalidTypeException;
import heap.Scan;
import heap.Tuple;

import java.io.IOException;
import java.util.ArrayList;

import javax.xml.bind.annotation.XmlElementDecl.GLOBAL;

import diskmgr.Page;

import bufmgr.BufMgrException;
import bufmgr.BufferPoolExceededException;
import bufmgr.HashEntryNotFoundException;
import bufmgr.HashOperationException;
import bufmgr.InvalidFrameNumberException;
import bufmgr.PageNotReadException;
import bufmgr.PagePinnedException;
import bufmgr.PageUnpinnedException;
import bufmgr.ReplacerException;

public class ExternalIterator extends Iterator {
	// this class will be used to return the next tuples in unsorted order

	private RID currentRID = null;
	private Tuple currentTuple = null;
	private boolean endOfScan = false;
	private Scan scan = null;

	public ExternalIterator(Heapfile heapFile)
			throws InvalidTupleSizeException, IOException {
		scan = new Scan(heapFile);
		currentRID = new RID();
	}

	public Tuple get_next() throws IOException, JoinsException, IndexException,
			InvalidTupleSizeException, InvalidTypeException,
			PageNotReadException, TupleUtilsException, PredEvalException,
			SortException, LowMemException, UnknowAttrType,
			UnknownKeyTypeException, Exception {
		if (endOfScan)
			return null;
		currentTuple = scan.getNext(currentRID); // note that current RID is set
		// to current tuple too
		if (currentTuple == null)
			endOfScan = true; // this means i have no Records
		return currentTuple ;
		
//		Tuple toBeReturned = new Tuple(currentTuple);
//		currentTuple = scan.getNext(currentRID);
//		if (currentRID == null)
//			endOfScan = true;
//		return toBeReturned;
	}

	public RID getcurrentrid() {
		return currentRID;
	}

	public ArrayList<Object> sort(ArrayList<Object> list, int type) {
		// sort array of Integers
		if (type == global.AttrType.attrInteger) {
			int[] array = new int[list.size()];
			for (int i = 0; i < array.length; i++) {
				array[i] = (Integer) list.get(i);
			}
			quickSortIntegers(array, 0, array.length - 1);

			ArrayList<Object> returned = new ArrayList<Object>();
			for (int i = 0; i < array.length; i++) {
				returned.add(array[i]);
			}
			return returned;

			// sort array of strings
		} else if (type == global.AttrType.attrString) {
			String[] array = new String[list.size()];
			for (int i = 0; i < array.length; i++) {
				array[i] = (String) list.get(i);
			}
			quickSortStrings(array, 0, array.length - 1);

			ArrayList<Object> returned = new ArrayList<Object>();
			for (int i = 0; i < array.length; i++) {
				returned.add(array[i]);
			}
			return returned;
		}
		else {
			throw new IllegalStateException("The type is nor integer nor string");
		}
	}

	// ------------------------------------
	// Methods to sort Strings

	public void quickSortStrings(String[] a, int from, int to) {
		if (from >= to)
			return; // there are no elements to sort
		/*
		 * Partition array such that the elements a[from]..a[p] (left partition)
		 * are less than the elements a[p+1]..a[to] (right partition)
		 */
		int p = partitionStrings(a, from, to);
		quickSortStrings(a, from, p); // sort left partition
		quickSortStrings(a, p + 1, to); // sort right partition
	}

	private int partitionStrings(String[] a, int from, int to) {
		String pivot = a[from];
		int i = from - 1;
		int j = to + 1;
		while (i < j) {
			i++;
			while (a[i].compareTo(pivot) < 0)
				i++;
			j--;
			while (a[j].compareTo(pivot) > 0)
				j--;
			if (i < j)
				swapStrings(a, i, j);
		}
		return j;
	}

	private void swapStrings(String[] a, int i, int j) {
		String temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}

	// --------------------------------------
	// Methods to sort Integers
	public void quickSortIntegers(int[] a, int from, int to) {
		if (from >= to)
			return; // there are no elements to sort
		/*
		 * Partition array such that the elements a[from]..a[p] (left partition)
		 * are less than the elements a[p+1]..a[to] (right partition)
		 */
		int p = partitionIntegers(a, from, to);
		quickSortIntegers(a, from, p); // sort left partition
		quickSortIntegers(a, p + 1, to); // sort right partition
	}

	private int partitionIntegers(int[] a, int from, int to) {
		int pivot = a[from];
		int i = from - 1;
		int j = to + 1;
		while (i < j) {
			i++;
			while (a[i] < pivot)
				i++;
			j--;
			while (a[j] > pivot)
				j--;
			if (i < j)
				swapIntegers(a, i, j);
		}
		return j;
	}

	private void swapIntegers(int[] a, int i, int j) {
		int temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}

	@Override
	public void close() throws IOException, JoinsException, SortException,
			IndexException {
	}
}